﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Net.Sockets;
using System.Timers;
using Reborn_WorldServer;
using Reborn_WorldServer.App1AppHandler;

namespace Reborn_Server.App1AppHandler
{
    public class Trainer : Creature
    {
        public List<TrainerSpell> TrainerSpells = new List<TrainerSpell>();
        public List<TrainerWeaponSkill> TrainerWeaponSkills = new List<TrainerWeaponSkill>();

        private string _trainsSkill = "";
        public string TrainsSkill
        {
            set 
            { 
                _trainsSkill = value;
                if (_trainsSkill == "Holy")
                {
                    Timer_MessageBroadcast.Start();
                    Timer_Action.Start();
                }
            }
            get { return _trainsSkill; }
        }

        private Timer Timer_MessageBroadcast = new Timer(1000 * 45);
        private Timer Timer_Action = new Timer(5000);

        public Trainer(AppHandler2 gameHander) : base(gameHander) 
        {
            Timer_MessageBroadcast.Elapsed += new ElapsedEventHandler(Timer_MessageBroadcast_Elapsed);
            Timer_MessageBroadcast.AutoReset = true;

            Timer_Action.Elapsed += new ElapsedEventHandler(Timer_Action_Elapsed);
            Timer_Action.AutoReset = true;
        }

        void Timer_Action_Elapsed(object sender, ElapsedEventArgs e)
        {
            Map currentMap = Managers.GameHandler.GetMap(this.MapID, this.Instance);

            CorpseCharacter corpse = currentMap.LootMngr.GetFirstCharacterCorpse(this.MapX, this.MapY);
            if (corpse != null)
                Managers.GameHandler.Resurrect(corpse.MyCharacter, this.MapID, this.MapX, this.MapY, 0, true);
        }

        void Timer_MessageBroadcast_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (this.TrainsSkill != "Holy")
                return;

            LockItem lockItem = Managers.GameHandler.GetLockItem(this.MapID, this.Instance);
            lock (lockItem.LockObj)
            {
                List<MapItem> MapItemsWithin4 = new List<MapItem>();
                Map currentMap = Managers.GameHandler.GetMap(this.MapID, this.Instance);
                {
                    foreach (MapItem mapitem in currentMap.MapItems)
                    {
                        if (Math.Abs(mapitem.MapX - this.MapX) <= 4 && Math.Abs(mapitem.MapY - this.MapY) <= 4)
                            MapItemsWithin4.Add(mapitem);
                    }
                }
                Message message = new Message();
                message.CreatureID = this.CreatureID;
                message.Type = "say";
                message.Text = this.Name + " says: Bring me your fallen comrades! Place their lifeless bodies at my feet and I shall raise them as if they never died!";

                this.MessageBroadcast(MapItemsWithin4, message, false);
            }
        }

        public override int HP
        {
            set
            {
                base.HP = base.MaxHP;
            }
        }

        public override bool grantExpTo(Character character)
        {
            return false;
        }

        public TrainerSpell getLevel1Spell()
        {
            foreach (TrainerSpell spell in TrainerSpells)
            {
                if (spell.spellIcon.LevelRequired == 1)
                    return spell;
            }
            return null;
        }

        public void OpenTrainerWindow(Character character)
        {
            if (this.MapID != character.MapID ||
                Math.Abs(this.MapX - character.MapX) > 2 || Math.Abs(this.MapY - character.MapY) > 2)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Trainer is to far away";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                return;
            }

            TrainerData trainerData = new TrainerData();
            trainerData.TrainerCreatureID = CreatureID;
            trainerData.TrainerName = Name;
            trainerData.TrainsSkill = TrainsSkill;
            trainerData.CharacterSkill = character.skillManager.GetCurrentLevel(TrainsSkill);
            trainerData.TrainedTo = character.skillManager.GetTrainedToLevel(TrainsSkill);

            if (trainerData.CharacterSkill == 0)
            {
                TrainerSpell level1Spell = getLevel1Spell();
                if (level1Spell != null)
                    trainerData.AvailableTraining = level1Spell.overrideCost == -1 ? level1Spell.spellIcon.Cost : level1Spell.overrideCost;
                else
                    trainerData.AvailableTraining = 0;
            }
            else
                trainerData.AvailableTraining = character.skillManager.GetAvailableTraining(TrainsSkill);

            trainerData.CharacterCoins = character.Coins;

            trainerData.TotalMagicLevels = character.skillManager.getTotalSpellLevels();
            trainerData.RequiredMagicLevels = character.skillManager.getRequiredSpellLevelsForThisSchool();
            trainerData.CurrentSchoolsKnown = character.skillManager.getTotalKnownSchools();
            trainerData.NextSchoolRequiredLevels = character.skillManager.getRequiredSpellLevelsForNextSchool();

            foreach (TrainerSpell trainerSpell in TrainerSpells)
            {
                TrainerSpell ts = new TrainerSpell();
                ts.spellIcon = trainerSpell.spellIcon;
                ts.overrideCost = trainerSpell.overrideCost;

                decimal currentLevel = character.skillManager.GetCurrentLevel(TrainsSkill);
                if (trainerSpell.spellIcon.LevelRequired > currentLevel)
                {
                    ts.purchaseStatus = "unavailable";
                    trainerData.TrainerSpells.Add(ts);
                    continue;
                }

                bool hasSpell = false;
                foreach (SpellPage spellPage in character.spellManager.SpellPages)
                {
                    if (spellPage != null)
                    {
                        foreach (SpellIcon spellIcon in spellPage.SpellIcons)
                        {
                            if (spellIcon != null && spellIcon.ID_DB == trainerSpell.spellIcon.ID_DB)
                            {
                                hasSpell = true;
                                break;
                            }
                        }
                    }
                }
                if (hasSpell == false)
                    ts.purchaseStatus = "available";
                else
                    ts.purchaseStatus = "purchased";

                trainerData.TrainerSpells.Add(ts);
            }

            foreach (TrainerWeaponSkill trainerWeaponSkill in TrainerWeaponSkills)
            {
                TrainerWeaponSkill ts = new TrainerWeaponSkill();
                ts.weaponSkill = trainerWeaponSkill.weaponSkill;
                ts.overrideCost = trainerWeaponSkill.overrideCost;

                decimal currentLevel = character.skillManager.GetCurrentLevel(TrainsSkill);
                if (trainerWeaponSkill.weaponSkill.LevelRequired > currentLevel)
                {
                    ts.purchaseStatus = "unavailable";
                    trainerData.TrainerWeaponSkills.Add(ts);
                    continue;
                }

                if (character.weaponSkillManager.hasSkill(trainerWeaponSkill.weaponSkill.ID_DB) == false)
                    ts.purchaseStatus = "available";
                else
                    ts.purchaseStatus = "purchased";

                trainerData.TrainerWeaponSkills.Add(ts);
            }

            try
            {
                character.ClientSocket.socket.BeginSend(trainerData.toXML());
            }
            catch { }
        }

        public void Train(Character character, int numCoins)
        {
            if (character.Coins < numCoins)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "You do not have enough coins";
                
                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            if (character.skillManager.GetAvailableTraining(TrainsSkill) < numCoins)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Not enough available training";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            if (this.MapID != character.MapID ||
                Math.Abs(this.MapX - character.MapX) > 2 || Math.Abs(this.MapY - character.MapY) > 2)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Trainer is to far away";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            //Attempting to learn spell school
            if (numCoins == 0 && character.skillManager.GetCurrentLevel(TrainsSkill) == 0)
            {
                int learningCost = 0;

                TrainerSpell level1Spell = getLevel1Spell();
                if (level1Spell != null)
                    learningCost = level1Spell.overrideCost == -1 ? level1Spell.spellIcon.Cost : level1Spell.overrideCost;

                if (character.Coins < learningCost)
                {
                    character.SendMessage("You do not have enough coins!", "server");
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    sendErrorNotification(character);
                    return;
                }

                //Make sure the character has enough spell levels to learn this school (Should never need this, just incase someone is sending bad requests)
                if (character.skillManager.getRequiredSpellLevelsForThisSchool() <= character.skillManager.getTotalSpellLevels())
                {
                    character.SendMessage("Server: You have learned " + TrainsSkill + "!", "server");
                    character.PlaySound("SkillUp", character.MapX, character.MapY);
                    character.skillManager.AddExp(TrainsSkill, 1);

                    if (level1Spell != null)
                        BuySpell(character, level1Spell.spellIcon.ID_DB);

                    return;
                }
            }
            //Is training
            else
            {
                character.Coins = character.Coins - numCoins;
                character.skillManager.AddTraining(TrainsSkill, numCoins);
                character.Update_Character();
                character.updateWeight();

                character.PlaySound("CashRegister", character.MapX, character.MapY);
                character.SendMessage("You purchase " + numCoins.ToString() + " training in " + this.TrainsSkill + " skill.", "server");
            }

            //Refresh Players Window
            OpenTrainerWindow(character);
        }

        public void BuySkill(Character character, int skillDB_ID)
        {
            if (this.MapID != character.MapID ||
                Math.Abs(this.MapX - character.MapX) > 2 || Math.Abs(this.MapY - character.MapY) > 2)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Trainer is to far away";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            //Get Spell to buy
            TrainerWeaponSkill trainerSkillToBuy = null;
            foreach (TrainerWeaponSkill trainerSkill in TrainerWeaponSkills)
            {
                if (trainerSkill.weaponSkill.ID_DB == skillDB_ID)
                {
                    trainerSkillToBuy = trainerSkill;
                    break;
                }
            }

            if (trainerSkillToBuy == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find skill " + trainerSkillToBuy.weaponSkill.Name;

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            if (character.weaponSkillManager.hasSkill(skillDB_ID) == true)
            {
                character.PlaySound("Ding", character.MapX, character.MapY);
                character.SendMessage("You already own " + trainerSkillToBuy.weaponSkill.Name, "server");
                sendErrorNotification(character);
                return;
            }

            int spellCost = trainerSkillToBuy.weaponSkill.Cost;
            if (trainerSkillToBuy.overrideCost != -1)
                spellCost = trainerSkillToBuy.overrideCost;

            if (character.Coins < spellCost)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Not enough coins to purchase " + trainerSkillToBuy.weaponSkill.Name;

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            character.Coins = character.Coins - spellCost;
            character.Update_Character();
            character.updateWeight();

            character.PlaySound("CashRegister", character.MapX, character.MapY);

            Message msg = new Message();
            msg.CreatureID = character.CreatureID;
            msg.Type = "server";
            msg.Text = "Server: You purchase " + trainerSkillToBuy.weaponSkill.Name;

            character.AddMessage(msg);

            character.weaponSkillManager.addSkill(trainerSkillToBuy.weaponSkill);

            //Refresh Players Window
            OpenTrainerWindow(character);
        }

        public void BuySpell(Character character, int spellDB_ID)
        {
            if (this.MapID != character.MapID ||
                Math.Abs(this.MapX - character.MapX) > 2 || Math.Abs(this.MapY - character.MapY) > 2)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Trainer is to far away";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            //Get Spell to buy
            TrainerSpell trainerSpellToBuy = null;
            foreach (TrainerSpell trainerSpell in TrainerSpells)
            {
                if (trainerSpell.spellIcon.ID_DB == spellDB_ID)
                {
                    trainerSpellToBuy = trainerSpell;
                    break;
                }
            }

            if (trainerSpellToBuy == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find spell " + trainerSpellToBuy.spellIcon.Name;

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            for (int y = 0; y < character.spellManager.SpellPages.Length; y++)
            {
                if (character.spellManager.SpellPages[y] != null)
                {
                    for (int x = 0; x < character.spellManager.SpellPages[y].SpellIcons.Length; x++)
                    {
                        if (y == 0 && x > 5)
                            break;

                        if (character.spellManager.SpellPages[y].SpellIcons[x] != null &&
                            character.spellManager.SpellPages[y].SpellIcons[x].ID_DB == trainerSpellToBuy.spellIcon.ID_DB)
                        {
                            character.PlaySound("Ding", character.MapX, character.MapY);
                            character.SendMessage("You already own " + trainerSpellToBuy.spellIcon.Name, "server");
                            sendErrorNotification(character);
                            return;
                        }
                    }
                }
            }

            int spellCost = trainerSpellToBuy.spellIcon.Cost;
            if (trainerSpellToBuy.overrideCost != -1)
                spellCost = trainerSpellToBuy.overrideCost;

            if (character.Coins < spellCost)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Not enough coins to purchase " + trainerSpellToBuy.spellIcon.Name;

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);
                sendErrorNotification(character);
                return;
            }

            character.Coins = character.Coins - spellCost;
            character.Update_Character();
            character.updateWeight();

            character.PlaySound("CashRegister", character.MapX, character.MapY);

            Message msg = new Message();
            msg.CreatureID = character.CreatureID;
            msg.Type = "server";
            msg.Text = "Server: You purchase " + trainerSpellToBuy.spellIcon.Name;

            character.AddMessage(msg);
            

            bool foundSlot = false;
            SpellPage spellPageToUpdate = null;
            for (int y = 0; y < character.spellManager.SpellPages.Length; y++)
            {
                if (character.spellManager.SpellPages[y] == null)
                {
                    character.spellManager.SpellPages[y] = new SpellPage();
                    character.spellManager.SpellPages[y].PageNumber = y;
                }

                for (int x = 0; x < character.spellManager.SpellPages[y].SpellIcons.Length; x++)
                {
                    if (y == 0 && x > 5)
                        break;

                    if (character.spellManager.SpellPages[y].SpellIcons[x] == null)
                    {
                        foundSlot = true;
                        character.spellManager.SpellPages[y].SpellIcons[x] = trainerSpellToBuy.spellIcon;
                        break;
                    }
                }
                if (foundSlot == true)
                {
                    spellPageToUpdate = character.spellManager.SpellPages[y];
                    break;
                }
            }
            character.AddSpellPages(spellPageToUpdate);

            //Refresh Players Window
            OpenTrainerWindow(character);
        }
        private void sendErrorNotification(Character character)
        {
            try
            {
                character.ClientSocket.socket.BeginSend("<trainererror />");
            }
            catch { }
        }
    }
}
